package mymongo

import (
    "context"
    //"fmt"
    "log"
    //"time"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo/options"
    "go.mongodb.org/mongo-driver/mongo/readpref"
)
 

type Myclient struct {
	Client 		*mongo.Client
	Cur 		*mongo.Collection
	Barrage 	*mongo.Collection
	Comment		*mongo.Collection
    Count   	int64
} 

type Mydata struct {
	Id    		string `json:"id"`
	Type  		string `json:"type"`
	Name  		string `json:"name"`
	Time  		string `json:"time"`
	Suffix 		string `json:"suffix"`
	Image       string `json:"image"`
}

type Barrage_comments struct {
	Id 		string  	  
	Data    [][]interface{}    
}

type MyBarrage struct {
	Author  string
	Color 	int64
	Id 		string
	Text    string
	Time    float64
	Type    int64
}

type Retdate struct {
	Type string
	Code int64
	Mesg string
}

func InitDB(table string, coltion string, barrage string, comment string) (*Myclient, error) {
    clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
    ctx := context.TODO()
    client, err := mongo.Connect(ctx, clientOptions)
    Coltion_clent  := client.Database(table).Collection(coltion)
    Barrage_clent  := client.Database(table).Collection(barrage)
    Comment_clent  := client.Database(table).Collection(comment)
    err = client.Ping(ctx, readpref.Primary())
    if err != nil {
        return nil, err
    }
    //opts := options.EstimatedDocumentCount().SetMaxTime(10 * time.Second)
	count, _ := Coltion_clent.EstimatedDocumentCount(ctx)
    mclient := &Myclient{client, Coltion_clent, Barrage_clent, Comment_clent, count}
    return mclient, nil
}

func (Mclient *Myclient) MyInItDB() {
	ctx := context.TODO()
	Mclient.Cur.DeleteMany(ctx, bson.D{{}})
	Mclient.Barrage.DeleteMany(ctx, bson.D{{}})
	Mclient.Comment.DeleteMany(ctx, bson.D{{}})
	Mclient.Count, _ = Mclient.Cur.EstimatedDocumentCount(ctx)
}

func (Mclient *Myclient) FindSeekSearch(search string) int64 {
	msearch := bson.D{}
	search_re := `.*` + search + `.*`
	msearch = append(msearch, bson.E{
		Key : "name",
		Value: bson.M{"$regex": primitive.Regex{Pattern: search_re, Options:"i"}},
	})
	count, _ := Mclient.Cur.CountDocuments(context.TODO(), msearch)
	return count
}


func (Mclient *Myclient) FindSeekAll() int64 {
	count, _ := Mclient.Cur.EstimatedDocumentCount(context.TODO())
	return count
}


func (Mclient *Myclient) FindAll(limit int64, page int64, search string) (*[]*Mydata, *Retdate){
	var retdata []*Mydata
	msearch := bson.D{}
	results := &Retdate{"FindALL", 1, "succeed"}
	ctx := context.TODO()
	findOptions := options.Find()
	findOptions.SetLimit(limit)
	findOptions.SetSkip((limit * page) - page)
	if search != "" {
		search_re := `.*` + search + `.*`
		msearch = append(msearch, bson.E{
			Key : "name",
			Value: bson.M{"$regex": primitive.Regex{Pattern: search_re, Options:"i"}},
		})
	}
	cur, err := Mclient.Cur.Find(ctx, msearch, findOptions)
	if err != nil {
		results.Mesg = err.Error()
		results.Code = 0
	}
	for cur.Next(ctx) {
	  	var result Mydata
	  	err := cur.Decode(&result)
		if err != nil {
	   		log.Fatal(err)
		}else{
			retdata = append(retdata, &result)
		}
	}
	if err := cur.Err(); err != nil {
		results.Mesg = err.Error()
		results.Code = 0
	}
	cur.Close(ctx)
	return &retdata, results
}

func (Mclient *Myclient) FindOne(id string) (*Mydata, *Retdate) {
	var result  Mydata
	var results Retdate
	filter := bson.D{{"id", id}}
	err := Mclient.Cur.FindOne(context.TODO(), filter).Decode(&result)
	if err == nil {
		results = Retdate{"FindOne", 1, "succeed"}
	}else{
		results = Retdate{"FindOne", 0, err.Error()}
	}
	return &result, &results
}

func (Mclient *Myclient) Insert(id string, _type string, name string, time string, suffix string) *Retdate {
	results := &Retdate{"Insert", 1, "succeed"}
	ctx := context.TODO()
	//Mclient.Client.Ping(ctx, nil)
	_, err := Mclient.Cur.InsertOne(ctx, Mydata{id, _type, name, time, suffix, ""})
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}else{
		Mclient.Count++
	}
	return results
}

func (Mclient *Myclient) Delete(id string) *Retdate {
	results := &Retdate{"Delete", 1, "succeed"}
	filter := bson.D{{"id", id}}
	_, err := Mclient.Cur.DeleteMany(context.TODO(), filter)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}else{
		Mclient.Count--
	}
	return results
}

func (Mclient *Myclient) Update(name string, time string, id string, _type string, suffix string) *Retdate {
	results := &Retdate{"Update", 1, "succeed"}
	filter := bson.D{{"id",id}}
	update := bson.D{
		{"$set", bson.D{
		{"name", name}, {"time", time}, {"type", _type}, {"suffix", suffix}},
	}}
	_, err := Mclient.Cur.UpdateOne(context.TODO(), filter, update)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}

func (Mclient *Myclient) Update_Coverv(id string, pngname string) *Retdate {
	results := &Retdate{"Update", 1, "succeed"}
	filter := bson.D{{"id",id}}
	update := bson.D{
		{"$set", bson.D{
		{"image", pngname}},
	}}
	_, err := Mclient.Cur.UpdateOne(context.TODO(), filter, update)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}

func (Mclient *Myclient) Upd_barrage(result *Barrage_comments) *Retdate {
	results := &Retdate{"Upd_barrage", 1, "succeed"}
	_, err := Mclient.Barrage.InsertOne(context.TODO(), result)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}

func (Mclient *Myclient) Get_barrage(id string) (*Barrage_comments, *Retdate) {
	var result  Barrage_comments
	results := &Retdate{"Get_barrage", 1, "succeed"}
	filter := bson.D{{"id", id}}
	err := Mclient.Barrage.FindOne(context.TODO(), filter).Decode(&result)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return &result, results
}

func (Mclient *Myclient) Add_barrage(data *MyBarrage) *Retdate {
	results := &Retdate{"Add_barrage", 1, "succeed"}
	filter := bson.M{"id": data.Id}
	update := bson.M{"$push": bson.M{"data": []interface{}{data.Time, data.Type, data.Color, data.Author, data.Text}}}
	opts := options.Update().SetUpsert(true)
	_, err := Mclient.Barrage.UpdateOne(context.TODO(), filter, update, opts)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}


func (Mclient *Myclient) Del_barrage(data *MyBarrage) *Retdate {
	results := &Retdate{"Del_barrage", 1, "succeed"}
	filter := bson.M{"id": data.Id}
	update := bson.M{"$pull": bson.M{"data": []interface{}{data.Time, data.Type, data.Color, data.Author, data.Text}}}
	_, err := Mclient.Barrage.UpdateOne(context.TODO(), filter, update)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}

func (Mclient *Myclient) Get_comment(id string) (*Barrage_comments, *Retdate) {
	var result  Barrage_comments
	results := &Retdate{"Get_comment", 1, "succeed"}
	filter := bson.D{{"id", id}}
	err := Mclient.Comment.FindOne(context.TODO(), filter).Decode(&result)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return &result, results
}


func (Mclient *Myclient) Add_comment(data *MyBarrage) *Retdate {
	results := &Retdate{"Add_comment", 1, "succeed"}
	filter := bson.M{"id": data.Id}
	update := bson.M{"$push": bson.M{"data": []interface{}{data.Time, data.Type, data.Color, data.Author, data.Text}}}
	opts := options.Update().SetUpsert(true)
	_, err := Mclient.Comment.UpdateOne(context.TODO(), filter, update, opts)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}

func (Mclient *Myclient) Del_comment(data *MyBarrage) *Retdate {
	results := &Retdate{"Del_comment", 1, "succeed"}
	filter := bson.M{"id": data.Id}
	update := bson.M{"$pull": bson.M{"data": []interface{}{data.Time, data.Type, data.Color, data.Author, data.Text}}}
	_, err := Mclient.Comment.UpdateOne(context.TODO(), filter, update)
	if err != nil {
	 	results.Mesg = err.Error()
	 	results.Code = 0
	}
	return results
}